package com.classic.common;

import ohos.aafwk.ability.Ability;
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import java.util.ArrayList;

public class MultipleStatusView extends DependentLayout {
    private static final int ONE = 1;
    private static final String COLON = ":";
    private static final String HINT = "Layout params is null.";
    private static final String TAG = "MultipleStatusView";
    private static final String VIEW_EMPTY = "emptyView";
    private static final String VIEW_ERROR = "errorView";
    private static final String VIEW_LOADING = "loadingView";
    private static final String VIEW_NETWORK = "noNetworkView";
    private static final String VIEW_CONTENT = "contentView";
    private static final LayoutConfig DEFAULT_LAYOUT_PARAMS =
            new LayoutConfig(LayoutConfig.MATCH_PARENT,
                    LayoutConfig.MATCH_PARENT);
    private static final int STATUS_CONTENT = 0x00;
    private static final int STATUS_LOADING = 0x01;
    private static final int STATUS_EMPTY = 0x02;
    private static final int STATUS_ERROR = 0x03;
    private static final int STATUS_NO_NETWORK = 0x04;
    private static final int NULL_RESOURCE_ID = -1;
    private Component mEmptyView;
    private Component mErrorView;
    private Component mLoadingView;
    private Component mNoNetworkView;
    private Component mContentView;
    private int mEmptyViewResId = ResourceTable.Layout_empty_view;
    private int mErrorViewResId = ResourceTable.Layout_error_view;
    private int mLoadingViewResId = ResourceTable.Layout_loading_view;
    private int mNoNetworkViewResId = ResourceTable.Layout_no_network_view;
    private int mContentViewResId = NULL_RESOURCE_ID;
    private int mViewStatus = ONE;
    private int mHintResId = ONE;
    private final LayoutScatter mInflater;
    private ClickedListener mOnRetryClickListener;
    private OnViewStatusChangeListener mViewStatusListener;
    private final EventHandler handler;
    private final ArrayList<Integer> mOtherIds = new ArrayList<>();

    /**
     * 构造方法
     *
     * @param context context
     */
    public MultipleStatusView(Context context) {
        this(context, null);
    }

    /**
     * 构造方法
     *
     * @param context context
     * @param attrs   attrs
     */
    public MultipleStatusView(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * 构造方法
     *
     * @param context      context
     * @param attrs        attrs
     * @param defStyleAttr defStyleAttr
     */
    public MultipleStatusView(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, null);
        handler = new EventHandler(EventRunner.getMainEventRunner());
        if (null != attrs) {
            boolean isPresent = attrs.getAttr(VIEW_EMPTY).isPresent();
            String viewString;
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_EMPTY).get().getStringValue();
                if (viewString.contains(COLON)) {
                    mEmptyViewResId = Integer.parseInt(viewString.split(COLON)[1]);
                }
            }
            isPresent = attrs.getAttr(VIEW_CONTENT).isPresent();
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_CONTENT).get().getStringValue();
                if (viewString.contains(COLON)) {
                    mContentViewResId = Integer.parseInt(viewString.split(COLON)[1]);
                }
            }
            isPresent = attrs.getAttr(VIEW_ERROR).isPresent();
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_ERROR).get().getStringValue();
                if (viewString.contains(COLON)) {
                    mErrorViewResId = Integer.parseInt(viewString.split(COLON)[1]);
                }
            }
            isPresent = attrs.getAttr(VIEW_LOADING).isPresent();
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_LOADING).get().getStringValue();
                if (viewString.contains(COLON)) {
                    mLoadingViewResId = Integer.parseInt(viewString.split(COLON)[1]);
                }
            }
            isPresent = attrs.getAttr(VIEW_NETWORK).isPresent();
            if (isPresent) {
                viewString = attrs.getAttr(VIEW_NETWORK).get().getStringValue();
                if (viewString.contains(COLON)) {
                    mNoNetworkViewResId = Integer.parseInt(viewString.split(COLON)[1]);
                }
            }
        }
        mInflater = LayoutScatter.getInstance(getContext());
    }

    /**
     * 获取当前状态
     *
     * @return 视图状态
     */
    public int getViewStatus() {
        return mViewStatus;
    }

    /**
     * 设置重试点击事件
     *
     * @param onRetryClickListener 重试点击事件
     */
    public void setOnRetryClickListener(ClickedListener onRetryClickListener) {
        this.mOnRetryClickListener = onRetryClickListener;
    }

    /**
     * 显示空视图
     *
     * @param viewId 资源Id
     */
    public final void showEmpty(int viewId) {
        showEmpty(mEmptyViewResId, DEFAULT_LAYOUT_PARAMS, viewId);
    }

    /**
     * 显示空视图
     *
     * @param hintResId  自定义提示文本内容
     * @param viewId     资源Id
     * @param formatArgs 占位符参数
     */
    public final void showEmpty(int hintResId, int viewId, Object... formatArgs) {
        showEmpty(viewId);
        setStatusHintContent(mEmptyView, hintResId, formatArgs);
    }

    /**
     * 显示空视图
     *
     * @param hint   自定义提示文本内容
     * @param viewId 资源Id
     */
    public final void showEmpty(String hint, int viewId) {
        showEmpty(viewId);
        setStatusHintContent(mEmptyView, hint);
    }

    /**
     * 显示空视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     * @param viewId       资源Id
     */
    public final void showEmpty(int layoutId, ComponentContainer.LayoutConfig layoutParams, int viewId) {
        showEmpty(null == mEmptyView ? inflateView(layoutId) : mEmptyView, layoutParams, viewId);
    }

    /**
     * 显示空视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     * @param viewId       资源Id
     */
    public final void showEmpty(Component view, ComponentContainer.LayoutConfig layoutParams, int viewId) {
        checkNull(view, "Empty view is null.");
        checkNull(layoutParams, HINT);
        changeViewStatus(STATUS_EMPTY);
        if (null == mEmptyView) {
            mEmptyView = view;
            Component emptyRetryView = mEmptyView.findComponentById(viewId);
            if (null != mOnRetryClickListener && null != emptyRetryView) {
                emptyRetryView.setClickedListener(mOnRetryClickListener);
            }
            mOtherIds.add(mEmptyView.getId());
            addComponent(mEmptyView, 0, layoutParams);
        }
        showViewById(mEmptyView.getId());
    }

    /**
     * 显示错误视图
     *
     * @param viewId 资源Id
     */
    public final void showError(int viewId) {
        showError(mErrorViewResId, DEFAULT_LAYOUT_PARAMS, viewId);
    }

    /**
     * 显示错误视图
     *
     * @param hintResId  自定义提示文本内容
     * @param viewId     资源Id
     * @param formatArgs 占位符参数
     */
    public final void showError(int hintResId, int viewId, Object... formatArgs) {
        showError(viewId);
        setStatusHintContent(mErrorView, hintResId, formatArgs);
    }

    /**
     * 显示错误视图
     *
     * @param hint   自定义提示文本内容
     * @param viewId 资源Id
     */
    public final void showError(String hint, int viewId) {
        showError(viewId);
        setStatusHintContent(mErrorView, hint);
    }

    /**
     * 显示错误视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     * @param viewId       资源Id
     */
    public final void showError(int layoutId, ComponentContainer.LayoutConfig layoutParams, int viewId) {
        showError(null == mErrorView ? inflateView(layoutId) : mErrorView, layoutParams, viewId);
    }

    /**
     * 显示错误视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     * @param viewId       资源Id
     */
    public final void showError(Component view, ComponentContainer.LayoutConfig layoutParams, int viewId) {
        checkNull(view, "Error view is null.");
        checkNull(layoutParams, HINT);
        changeViewStatus(STATUS_ERROR);
        if (null == mErrorView) {
            mErrorView = view;
            Component errorRetryView = mErrorView.findComponentById(viewId);
            if (null != mOnRetryClickListener && null != errorRetryView) {
                errorRetryView.setClickedListener(mOnRetryClickListener);
            }
            mOtherIds.add(mErrorView.getId());
            addComponent(mErrorView, 0, layoutParams);
        }
        showViewById(mErrorView.getId());
    }

    /**
     * 显示加载中视图
     */
    public final void showLoading() {
        showLoading(mLoadingViewResId, DEFAULT_LAYOUT_PARAMS);


    }

    /**
     * 显示加载中视图
     *
     * @param hintResId  自定义提示文本内容
     * @param formatArgs 占位符参数
     */
    public final void showLoading(int hintResId, Object... formatArgs) {
        showLoading();
        setStatusHintContent(mLoadingView, hintResId, formatArgs);
    }

    /**
     * 显示加载中视图
     *
     * @param hint 自定义提示文本内容
     */
    public final void showLoading(String hint) {
        showLoading();
        setStatusHintContent(mLoadingView, hint);
    }

    /**
     * 显示加载中视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    public final void showLoading(int layoutId, ComponentContainer.LayoutConfig layoutParams) {
        showLoading(null == mLoadingView ? inflateView(layoutId) : mLoadingView, layoutParams);
    }

    /**
     * 显示加载中视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    public final void showLoading(Component view, ComponentContainer.LayoutConfig layoutParams) {
        checkNull(view, "Loading view is null.");
        checkNull(layoutParams, HINT);
        changeViewStatus(STATUS_LOADING);
        if (null == mLoadingView) {
            mLoadingView = view;
            mOtherIds.add(mLoadingView.getId());
            addComponent(mLoadingView, 0, layoutParams);
        }
        showViewById(mLoadingView.getId());
    }

    /**
     * 显示无网络视图
     *
     * @param viewId 资源Id
     */
    public final void showNoNetwork(int viewId) {
        showNoNetwork(mNoNetworkViewResId, DEFAULT_LAYOUT_PARAMS, viewId);
    }

    /**
     * 显示无网络视图
     *
     * @param hintResId  自定义提示文本内容
     * @param viewId     资源Id
     * @param formatArgs 占位符参数
     */
    public final void showNoNetwork(int hintResId, int viewId, Object... formatArgs) {
        showNoNetwork(viewId);
        setStatusHintContent(mNoNetworkView, hintResId, formatArgs);
    }

    /**
     * 显示无网络视图
     *
     * @param hint   自定义提示文本内容
     * @param viewId 资源Id
     */
    public final void showNoNetwork(String hint, int viewId) {
        showNoNetwork(viewId);
        setStatusHintContent(mNoNetworkView, hint);
    }

    /**
     * 显示无网络视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     * @param viewId       资源Id
     */
    public final void showNoNetwork(int layoutId, ComponentContainer.LayoutConfig layoutParams, int viewId) {
        showNoNetwork(null == mNoNetworkView ? inflateView(layoutId) : mNoNetworkView, layoutParams, viewId);
    }

    /**
     * 显示无网络视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     * @param viewId       资源Id
     */
    public final void showNoNetwork(Component view, ComponentContainer.LayoutConfig layoutParams, int viewId) {
        checkNull(view, "No network view is null.");
        checkNull(layoutParams, HINT);
        changeViewStatus(STATUS_NO_NETWORK);
        if (null == mNoNetworkView) {
            mNoNetworkView = view;
            Component noNetworkRetryView = mNoNetworkView.findComponentById(viewId);
            if (null != mOnRetryClickListener && null != noNetworkRetryView) {
                noNetworkRetryView.setClickedListener(mOnRetryClickListener);
            }
            mOtherIds.add(mNoNetworkView.getId());
            addComponent(mNoNetworkView, 0, layoutParams);
        }
        showViewById(mNoNetworkView.getId());
    }

    /**
     * 显示内容视图
     */
    public final void showContent() {
        changeViewStatus(STATUS_CONTENT);
        if (null == mContentView && mContentViewResId != NULL_RESOURCE_ID) {
            mContentView = mInflater.parse(mContentViewResId, null, false);
            addComponent(mContentView, 0, DEFAULT_LAYOUT_PARAMS);
        }
        showContentView();
    }

    /**
     * 显示内容视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    public final void showContent(int layoutId, ComponentContainer.LayoutConfig layoutParams) {
        showContent(inflateView(layoutId), layoutParams);
    }

    /**
     * 显示内容视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    public final void showContent(Component view, ComponentContainer.LayoutConfig layoutParams) {
        checkNull(view, "Content view is null.");
        checkNull(layoutParams, HINT);
        changeViewStatus(STATUS_CONTENT);
        clear(mContentView);
        mContentView = view;
        addComponent(mContentView, 0, layoutParams);
        showViewById(mContentView.getId());
    }

    private void setStatusHintContent(Component view, int resId, Object... formatArgs) {
        checkNull(view, "Target view is null.");
        setStatusHintContent(view, view.getContext().getString(resId, formatArgs));
    }

    private void setStatusHintContent(Component view, String hint) {
        checkNull(view, "Target view is null.");

        if (mHintResId != NULL_RESOURCE_ID) {
            Text hintView = (Text) view.findComponentById(mHintResId);
            hintView.setText(hint);
        } else {
            throw new NullPointerException("Not find the view ID `status_hint_content`");
        }
    }

    public void setStatusHintRes(int hintRes) {
        mHintResId = hintRes;
    }

    private Component inflateView(int layoutId) {
        return mInflater.parse(layoutId, null, false);
    }

    private void showViewById(int viewId) {
        final int childCount = getChildCount();
        for (int ii = 0; ii < childCount; ii++) {
            Component view = getComponentAt(ii);
            view.setVisibility(view.getId() == viewId ? Component.VISIBLE : Component.HIDE);
        }
    }

    private void showContentView() {
        final int childCount = getChildCount();
        for (int ii = 0; ii < childCount; ii++) {
            Component view = getComponentAt(ii);
            view.setVisibility(mOtherIds.contains(view.getId()) ? Component.HIDE : Component.VISIBLE);
        }
    }

    private void checkNull(Object object, String hint) {
        if (null == object) {
            throw new NullPointerException(hint);
        }
    }

    private void clear(Component views) {
        removeComponent(views);
    }

    /**
     * 视图状态改变接口
     *
     * @since 2021-05-13
     */
    public interface OnViewStatusChangeListener {

        /**
         * 视图状态改变时回调
         *
         * @param oldViewStatus 之前的视图状态
         * @param newViewStatus 新的视图状态
         */
        void onChange(int oldViewStatus, int newViewStatus);
    }

    /**
     * 设置视图状态改变监听事件
     *
     * @param onViewStatusChangeListener 视图状态改变监听事件
     */
    public void setOnViewStatusChangeListener(OnViewStatusChangeListener onViewStatusChangeListener) {
        this.mViewStatusListener = onViewStatusChangeListener;
    }

    /**
     * 改变视图状态
     *
     * @param newViewStatus 新的视图状态
     */
    private void changeViewStatus(int newViewStatus) {
        if (mViewStatus == newViewStatus) {
            return;
        }
        if (null != mViewStatusListener) {
            mViewStatusListener.onChange(mViewStatus, newViewStatus);
        }
        mViewStatus = newViewStatus;
    }


    private void setContentViewResId(int contentViewResId) {
        this.mContentViewResId = contentViewResId;
        this.mContentView = mInflater.parse(mContentViewResId, null, false);
        addComponent(mContentView, 0, DEFAULT_LAYOUT_PARAMS);
    }

    private void setContentView(ComponentContainer contentView) {
        this.mContentView = contentView;
        addComponent(mContentView, 0, DEFAULT_LAYOUT_PARAMS);
    }

    /**
     * 绑定数据
     *
     * @param ability           ability
     * @param rootAnchor         rootAnchor
     * @param xmlRootLayoutResId xmlRootLayoutResId
     * @return attach(defaultAnchor)
     */
    public static MultipleStatusView attach(Ability ability, int rootAnchor, int xmlRootLayoutResId) {
        if (NULL_RESOURCE_ID != rootAnchor) {
            ComponentContainer contentAnchor = (ComponentContainer) ability.findComponentById(rootAnchor);
            if (null != contentAnchor) {
                attach(contentAnchor);
            }
        }
        ComponentContainer defaultAnchor = (ComponentContainer) ability.findComponentById(xmlRootLayoutResId);
        return attach(defaultAnchor);
    }

    /**
     * 绑定数据
     *
     * @param rootAnchor rootAnchor
     * @return statusView
     * @throws IllegalArgumentException Exception
     */
    public static MultipleStatusView attach(ComponentContainer rootAnchor) {
        if (null == rootAnchor) {
            throw new IllegalArgumentException("root Anchor Component can't be null");
        }
        ComponentContainer parent = (ComponentContainer) rootAnchor.getComponentParent();
        int anchorIndex = parent.getChildIndex(rootAnchor);
        if (NULL_RESOURCE_ID != anchorIndex) {
            parent.removeComponent(rootAnchor);
            MultipleStatusView statusView = new MultipleStatusView(rootAnchor.getContext());
            statusView.setContentView(rootAnchor);
            ComponentContainer.LayoutConfig config = rootAnchor.getLayoutConfig();
            parent.addComponent(statusView, anchorIndex, config);
            return statusView;
        }
        return new MultipleStatusView(parent.getContext());
    }

    /**
     * 执行同步任务
     *
     * @param runnable runnable
     */
    public void removeCallbacks(Runnable runnable) {
        handler.removeTask(runnable);
    }

    /**
     * 延时执行任务
     *
     * @param runnable runnable
     * @param delay    delay
     */
    public void postDelayed(Runnable runnable, int delay) {
        handler.postTask(runnable, delay);
    }
}

